﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace ProDeletor
{
    class Deleter
    {
        private DirectoryInfo rootFolder;
        private bool emptyFolder = true;
        private bool recursive = true;
        private int timeToKeep;
        private bool useLog = false;
        private bool testMode = false;
        private bool archive;
        private string archivePath;
        private Log logFile;
        private string logPath;
        private int mode = 0;
        int folderCount = 0;
        int fileCount = 0;
        int deletedFolderCount = 0;
        int deletedFileCount = 0;
        private string fileMask;
        DateTime runTime;

        public Deleter(string rootFolder)
        {
            this.rootFolder = new DirectoryInfo(rootFolder);
        }

        public string FileMask
        {
            get { return this.fileMask; }
            set { fileMask = value; }
        }
        public bool UseRecursion
        {
            get { return this.recursive; }
            set { this.recursive = value; }
        }

        public bool DeleteEmptyFolders
        {
            get { return this.emptyFolder; }
            set { this.emptyFolder = value; }
        }

        public int TimeToKeep
        {
            get { return this.timeToKeep; }
            set { this.timeToKeep = value; }
        }

        public bool WriteLog
        {
            get { return this.useLog; }
            set { this.useLog = value; }
        }

        public bool TestMode
        {
            get { return this.testMode; }
            set { this.testMode = value; }
        }
        public string LogPath
        {
            get { return logPath; }
            set { logPath = value; }
        }

        public int Mode
        {
            get { return mode; }
            set { mode = value; }
        }

        public bool Archive
        {
            get { return archive; }
            set { archive = value; }
        }

        public string ArchivePath
        {
            get { return archivePath; }
            set { archivePath = value; }
        }

        public void runDelete()
        {
            fileCount = 0;
            deletedFileCount = 0;
            folderCount = 0;
            deletedFolderCount = 0;
            runTime = DateTime.Now;
            logFile = new Log(logPath);
            logFile.write("ProDeletor starting to check folder " + rootFolder.FullName);
            if (recursive)
            {
                DirectoryInfo[] folders;
                try
                {
                    folders = this.rootFolder.GetDirectories();
                }
                catch
                {
                    folders = null;
                }
                if (folders != null)
                {
                    foreach (DirectoryInfo subFolder in folders)
                    {
                        recursiveDelete(subFolder);
                    }
                }
            }
            deleteFiles(this.rootFolder, fileMask);
            logFile.write("ProDeletor check is done, " + fileCount + " file(s) in " + folderCount + " folder(s) checked, " +
                deletedFileCount + " file(s) and " + deletedFolderCount + " folder(s) deleted.");
            logFile.close();
        }

        private void recursiveDelete(DirectoryInfo folder)
        {
            DirectoryInfo[] subFolders = folder.GetDirectories();

            foreach (DirectoryInfo subFolder in subFolders)
            {
                recursiveDelete(subFolder);
            }
            // Delete all old files first
            deleteFiles(folder, fileMask);
            folderCount++;
            if (isFolderEmpty(folder))
            {
                // And if folder is empty, try to delete it
                if (useLog || testMode)
                    logFile.write("Deleting empty folder " + folder.FullName);
                if (!testMode && emptyFolder)
                {
                    try
                    {
                        folder.Delete();
                        deletedFolderCount++;
                    }
                    catch
                    {
                        if (useLog)
                            logFile.write("Cannot delete folder " + folder.FullName);
                    }
                }
            }
        }

        public void deleteFiles(DirectoryInfo folder, string fileMask)
        {
            string[] maskArray = fileMask.Split(',');
            foreach (string mask in maskArray)
            {
                FileInfo[] files;
                try
                {
                    files = folder.GetFiles(mask);
                }
                catch
                {
                    files = null;
                }
                if (files != null)
                {
                    foreach (FileInfo file in files)
                    {
                        DateTime fileTime = file.LastAccessTime;
                        if (mode == 1)
                            fileTime = file.LastWriteTime;
                        if (mode == 2)
                            fileTime = file.CreationTime;

                        TimeSpan span = runTime.Subtract(fileTime);
                        fileCount++;
                        if ((int)span.TotalMinutes > timeToKeep)
                        {
                            // If filetime is older than timeToKeep, delete it
                            if (useLog || testMode)
                                logFile.write("Deleting file " + file.FullName);
                            if (!testMode)
                            {
                                if (archive)
                                {
                                    if (archiveFile(file))
                                    {
                                        try
                                        {
                                            file.Delete();
                                            deletedFileCount++;
                                        }
                                        catch
                                        {
                                            if (useLog)
                                                logFile.write("Cannot delete file " + file.FullName);
                                        }
                                    }
                                    else
                                    {
                                        if (useLog)
                                            logFile.write("Cannot archive file " + file.FullName + ". File not deleted.");
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        file.Delete();
                                        deletedFileCount++;
                                    }
                                    catch
                                    {
                                        if (useLog)
                                            logFile.write("Cannot delete file " + file.FullName);
                                    }
                                }


                            }
                        }
                    }
                }
                else
                {
                    logFile.write("Target folder is unreachable.");
                }
            }
        }

        private bool archiveFile(FileInfo file)
        {
            string movedFile = file.Name;
            int counter = 0;
            Console.WriteLine(file.Name);
            while (File.Exists(archivePath + "\\" + movedFile))
            {
                string[] splittedFileName = splittedFileName = file.Name.Split('.');
                counter++;
                movedFile = splittedFileName[0] + '(' + counter.ToString() + ')';
                if (splittedFileName.Length > 1)
                    for (int i = 1; i < splittedFileName.Length; i++)
                        movedFile += "." + splittedFileName[i];
            }
            try
            {
                file.CopyTo(archivePath + "\\" + movedFile);
                if (useLog || testMode)
                    logFile.write("File " + file.FullName + " archived to " + archivePath + "\\" + movedFile);
                return true;
            }
            catch
            {
                return false;
            }
        }

        private bool isFolderEmpty(DirectoryInfo folder)
        {
            if (folder.GetFiles().Count() != 0)
                return false;
            if (folder.GetDirectories().Count() != 0)
                return false;
            return true;
        }
    }
}
